package com.cencat.user.dto;

import com.cencat.common.enums.GrantType;
import com.cencat.common.enums.DataScope;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.AllArgsConstructor;
import lombok.Builder;

import jakarta.validation.constraints.*;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Set;
import java.util.HashSet;

/**
 * 角色权限关联更新DTO
 * @author cencat
 * @since 2024-01-01
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class RolePermissionUpdateDTO {

    /**
     * 关联ID
     */
    @NotNull(message = "关联ID不能为空")
    @Min(value = 1, message = "关联ID必须大于0")
    private Long id;

    /**
     * 角色ID
     */
    @Min(value = 1, message = "角色ID必须大于0")
    private Long roleId;

    /**
     * 权限ID
     */
    @Min(value = 1, message = "权限ID必须大于0")
    private Long permissionId;

    /**
     * 授权类型（GRANT-授权，DENY-拒绝）
     */
    private GrantType grantType;

    /**
     * 数据权限范围（ALL-全部数据，DEPT-部门数据，DEPT_AND_CHILD-部门及以下数据，SELF-仅本人数据，CUSTOM-自定义数据）
     */
    private DataScope dataScope;

    /**
     * 自定义数据权限SQL条件
     */
    @Size(max = 1000, message = "自定义数据权限SQL条件长度不能超过1000个字符")
    private String dataCondition;

    /**
     * 生效时间
     */
    private LocalDateTime effectiveTime;

    /**
     * 失效时间
     */
    private LocalDateTime expiryTime;

    /**
     * 状态（true-启用，false-禁用）
     */
    private Boolean status;

    /**
     * 优先级（数值越大优先级越高）
     */
    @Min(value = 0, message = "优先级不能小于0")
    @Max(value = 999, message = "优先级不能大于999")
    private Integer priority;

    /**
     * 备注
     */
    @Size(max = 500, message = "备注长度不能超过500个字符")
    private String remark;

    /**
     * 更新人ID
     */
    @NotNull(message = "更新人ID不能为空")
    @Min(value = 1, message = "更新人ID必须大于0")
    private Long updateBy;

    /**
     * 操作类型（UPDATE-更新，EXTEND-延期，REVOKE-撤销，ACTIVATE-激活，DEACTIVATE-停用）
     */
    @NotNull(message = "操作类型不能为空")
    private OperationType operationType;

    /**
     * 延期天数（用于延期操作）
     */
    @Min(value = 1, message = "延期天数必须大于0")
    @Max(value = 3650, message = "延期天数不能超过3650天")
    private Integer extendDays;

    /**
     * 是否永久有效（用于延期操作）
     */
    private Boolean permanent;

    /**
     * 批量操作的ID列表
     */
    private List<Long> ids;

    /**
     * 是否发送通知
     */
    private Boolean sendNotification;

    /**
     * 通知方式（EMAIL-邮件，SMS-短信，SYSTEM-系统通知）
     */
    private List<String> notifyMethods;

    /**
     * 操作原因
     */
    @Size(max = 500, message = "操作原因长度不能超过500个字符")
    private String operationReason;

    /**
     * 是否强制更新（忽略冲突检查）
     */
    private Boolean forceUpdate;

    /**
     * 需要更新的字段集合
     */
    private Set<String> updateFields;

    /**
     * 版本号（用于乐观锁）
     */
    private Integer version;

    /**
     * 租户ID
     */
    private Long tenantId;

    /**
     * 操作类型枚举
     */
    public enum OperationType {
        UPDATE("更新"),
        EXTEND("延期"),
        REVOKE("撤销"),
        ACTIVATE("激活"),
        DEACTIVATE("停用"),
        CHANGE_PRIORITY("修改优先级"),
        CHANGE_DATA_SCOPE("修改数据权限"),
        CHANGE_GRANT_TYPE("修改授权类型");

        private final String description;

        OperationType(String description) {
            this.description = description;
        }

        public String getDescription() {
            return description;
        }
    }

    /**
     * 检查有效期设置是否合法
     * @return 是否合法
     */
    public boolean isValidityPeriodValid() {
        // 延期操作的特殊检查
        if (OperationType.EXTEND.equals(operationType)) {
            // 延期操作必须设置延期天数或永久有效
            if (Boolean.TRUE.equals(permanent)) {
                return extendDays == null; // 永久有效时不能设置延期天数
            } else {
                return extendDays != null && extendDays > 0; // 非永久有效时必须设置延期天数
            }
        }
        
        // 如果设置了永久有效，则不能设置失效时间
        if (Boolean.TRUE.equals(permanent)) {
            return expiryTime == null;
        }
        
        // 如果设置了生效时间和失效时间，失效时间必须晚于生效时间
        if (effectiveTime != null && expiryTime != null) {
            return expiryTime.isAfter(effectiveTime);
        }
        
        return true;
    }

    /**
     * 检查数据权限设置是否合法
     * @return 是否合法
     */
    public boolean isDataScopeValid() {
        // 如果数据权限范围为自定义，则必须提供自定义条件
        if (DataScope.CUSTOM.equals(dataScope)) {
            return dataCondition != null && !dataCondition.trim().isEmpty();
        }
        
        // 如果数据权限范围不是自定义，则不应该有自定义条件
        if (dataScope != null && !DataScope.CUSTOM.equals(dataScope)) {
            return dataCondition == null || dataCondition.trim().isEmpty();
        }
        
        return true;
    }

    /**
     * 检查操作类型是否合法
     * @return 是否合法
     */
    public boolean isOperationTypeValid() {
        if (operationType == null) {
            return false;
        }
        
        switch (operationType) {
            case EXTEND:
                // 延期操作必须设置延期天数或永久有效
                return (extendDays != null && extendDays > 0) || Boolean.TRUE.equals(permanent);
            case REVOKE:
                // 撤销操作不需要其他参数
                return true;
            case ACTIVATE:
            case DEACTIVATE:
                // 激活/停用操作不需要其他参数
                return true;
            case CHANGE_PRIORITY:
                // 修改优先级操作必须设置优先级
                return priority != null;
            case CHANGE_DATA_SCOPE:
                // 修改数据权限操作必须设置数据权限范围
                return dataScope != null;
            case CHANGE_GRANT_TYPE:
                // 修改授权类型操作必须设置授权类型
                return grantType != null;
            case UPDATE:
                // 更新操作至少要有一个更新字段
                return updateFields != null && !updateFields.isEmpty();
            default:
                return false;
        }
    }

    /**
     * 检查批量操作参数是否合法
     * @return 是否合法
     */
    public boolean isBatchOperationValid() {
        // 不能同时设置单个ID和批量ID
        if (id != null && ids != null && !ids.isEmpty()) {
            return false;
        }
        
        // 必须至少设置一个ID
        if (id == null && (ids == null || ids.isEmpty())) {
            return false;
        }
        
        return true;
    }

    /**
     * 检查通知方式是否合法
     * @return 是否合法
     */
    public boolean isNotifyMethodsValid() {
        if (!Boolean.TRUE.equals(sendNotification)) {
            return true; // 不发送通知时，通知方式可以为空
        }
        
        if (notifyMethods == null || notifyMethods.isEmpty()) {
            return false; // 发送通知时，必须指定通知方式
        }
        
        // 检查通知方式是否合法
        for (String method : notifyMethods) {
            if (!"EMAIL".equals(method) && !"SMS".equals(method) && !"SYSTEM".equals(method)) {
                return false;
            }
        }
        
        return true;
    }

    /**
     * 获取实际的ID列表
     * @return ID列表
     */
    public List<Long> getActualIds() {
        if (ids != null && !ids.isEmpty()) {
            return ids;
        }
        
        if (id != null) {
            return List.of(id);
        }
        
        return List.of();
    }

    /**
     * 检查是否为批量操作
     * @return 是否为批量操作
     */
    public boolean isBatchOperation() {
        return ids != null && ids.size() > 1;
    }

    /**
     * 获取预计更新的记录数量
     * @return 记录数量
     */
    public int getEstimatedUpdateCount() {
        return getActualIds().size();
    }

    /**
     * 添加更新字段
     * @param field 字段名
     */
    public void addUpdateField(String field) {
        if (updateFields == null) {
            updateFields = new HashSet<>();
        }
        updateFields.add(field);
    }

    /**
     * 移除更新字段
     * @param field 字段名
     */
    public void removeUpdateField(String field) {
        if (updateFields != null) {
            updateFields.remove(field);
        }
    }

    /**
     * 检查是否需要更新指定字段
     * @param field 字段名
     * @return 是否需要更新
     */
    public boolean shouldUpdateField(String field) {
        return updateFields != null && updateFields.contains(field);
    }

    /**
     * 设置快速操作 - 延期
     * @param days 延期天数
     */
    public void setQuickExtend(int days) {
        this.operationType = OperationType.EXTEND;
        this.extendDays = days;
        this.permanent = false;
    }

    /**
     * 设置快速操作 - 永久延期
     */
    public void setQuickExtendPermanent() {
        this.operationType = OperationType.EXTEND;
        this.permanent = true;
        this.extendDays = null;
    }

    /**
     * 设置快速操作 - 撤销
     */
    public void setQuickRevoke() {
        this.operationType = OperationType.REVOKE;
        this.status = false;
    }

    /**
     * 设置快速操作 - 激活
     */
    public void setQuickActivate() {
        this.operationType = OperationType.ACTIVATE;
        this.status = true;
    }

    /**
     * 设置快速操作 - 停用
     */
    public void setQuickDeactivate() {
        this.operationType = OperationType.DEACTIVATE;
        this.status = false;
    }

    /**
     * 设置快速操作 - 修改优先级
     * @param priority 新优先级
     */
    public void setQuickChangePriority(int priority) {
        this.operationType = OperationType.CHANGE_PRIORITY;
        this.priority = priority;
        addUpdateField("priority");
    }

    /**
     * 设置快速操作 - 修改数据权限
     * @param dataScope 数据权限范围
     */
    public void setQuickChangeDataScope(DataScope dataScope) {
        this.operationType = OperationType.CHANGE_DATA_SCOPE;
        this.dataScope = dataScope;
        if (dataScope != DataScope.CUSTOM) {
            this.dataCondition = null;
        }
        addUpdateField("dataScope");
        addUpdateField("dataCondition");
    }

    /**
     * 设置快速操作 - 修改自定义数据权限
     * @param condition 自定义条件
     */
    public void setQuickChangeCustomDataScope(String condition) {
        this.operationType = OperationType.CHANGE_DATA_SCOPE;
        this.dataScope = DataScope.CUSTOM;
        this.dataCondition = condition;
        addUpdateField("dataScope");
        addUpdateField("dataCondition");
    }

    /**
     * 设置快速操作 - 修改授权类型
     * @param grantType 授权类型
     */
    public void setQuickChangeGrantType(GrantType grantType) {
        this.operationType = OperationType.CHANGE_GRANT_TYPE;
        this.grantType = grantType;
        addUpdateField("grantType");
    }

    /**
     * 设置通知配置
     * @param sendNotification 是否发送通知
     * @param methods 通知方式
     */
    public void setNotificationConfig(boolean sendNotification, String... methods) {
        this.sendNotification = sendNotification;
        if (sendNotification && methods != null && methods.length > 0) {
            this.notifyMethods = List.of(methods);
        } else {
            this.notifyMethods = null;
        }
    }

    /**
     * 计算延期后的失效时间
     * @param currentExpiryTime 当前失效时间
     * @return 新的失效时间
     */
    public LocalDateTime calculateExtendedExpiryTime(LocalDateTime currentExpiryTime) {
        if (Boolean.TRUE.equals(permanent)) {
            return null; // 永久有效
        }
        
        if (extendDays != null && extendDays > 0) {
            LocalDateTime baseTime = currentExpiryTime != null ? currentExpiryTime : LocalDateTime.now();
            return baseTime.plusDays(extendDays);
        }
        
        return currentExpiryTime;
    }

    /**
     * 验证所有参数
     * @return 验证结果
     */
    public ValidationResult validate() {
        ValidationResult result = new ValidationResult();
        
        if (!isValidityPeriodValid()) {
            result.addError("有效期设置不合法");
        }
        
        if (!isDataScopeValid()) {
            result.addError("数据权限设置不合法");
        }
        
        if (!isOperationTypeValid()) {
            result.addError("操作类型设置不合法");
        }
        
        if (!isBatchOperationValid()) {
            result.addError("批量操作参数设置不合法");
        }
        
        if (!isNotifyMethodsValid()) {
            result.addError("通知方式设置不合法");
        }
        
        return result;
    }

    /**
     * 验证结果类
     */
    public static class ValidationResult {
        private boolean valid = true;
        private java.util.List<String> errors = new java.util.ArrayList<>();
        
        public void addError(String error) {
            this.valid = false;
            this.errors.add(error);
        }
        
        public boolean isValid() {
            return valid;
        }
        
        public java.util.List<String> getErrors() {
            return errors;
        }
        
        public String getErrorMessage() {
            return String.join("; ", errors);
        }
    }

    /**
     * 创建构建器
     * @return 构建器
     */
    public static RolePermissionUpdateDTOBuilder builder() {
        return new RolePermissionUpdateDTOBuilder();
    }

    /**
     * 创建简单的更新DTO
     * @param id 关联ID
     * @param updateBy 更新人ID
     * @return DTO对象
     */
    public static RolePermissionUpdateDTO createSimple(Long id, Long updateBy) {
        RolePermissionUpdateDTO dto = new RolePermissionUpdateDTO();
        dto.setId(id);
        dto.setUpdateBy(updateBy);
        dto.setOperationType(OperationType.UPDATE);
        return dto;
    }

    /**
     * 创建延期DTO
     * @param id 关联ID
     * @param updateBy 更新人ID
     * @param days 延期天数
     * @return DTO对象
     */
    public static RolePermissionUpdateDTO createExtend(Long id, Long updateBy, int days) {
        RolePermissionUpdateDTO dto = new RolePermissionUpdateDTO();
        dto.setId(id);
        dto.setUpdateBy(updateBy);
        dto.setQuickExtend(days);
        return dto;
    }

    /**
     * 创建撤销DTO
     * @param id 关联ID
     * @param updateBy 更新人ID
     * @param reason 撤销原因
     * @return DTO对象
     */
    public static RolePermissionUpdateDTO createRevoke(Long id, Long updateBy, String reason) {
        RolePermissionUpdateDTO dto = new RolePermissionUpdateDTO();
        dto.setId(id);
        dto.setUpdateBy(updateBy);
        dto.setOperationReason(reason);
        dto.setQuickRevoke();
        return dto;
    }

    /**
     * 创建批量操作DTO
     * @param ids ID列表
     * @param updateBy 更新人ID
     * @param operationType 操作类型
     * @return DTO对象
     */
    public static RolePermissionUpdateDTO createBatch(List<Long> ids, Long updateBy, OperationType operationType) {
        RolePermissionUpdateDTO dto = new RolePermissionUpdateDTO();
        dto.setIds(ids);
        dto.setUpdateBy(updateBy);
        dto.setOperationType(operationType);
        return dto;
    }

    /**
     * 创建修改优先级DTO
     * @param id 关联ID
     * @param updateBy 更新人ID
     * @param priority 新优先级
     * @return DTO对象
     */
    public static RolePermissionUpdateDTO createChangePriority(Long id, Long updateBy, int priority) {
        RolePermissionUpdateDTO dto = new RolePermissionUpdateDTO();
        dto.setId(id);
        dto.setUpdateBy(updateBy);
        dto.setQuickChangePriority(priority);
        return dto;
    }

    /**
     * 创建修改数据权限DTO
     * @param id 关联ID
     * @param updateBy 更新人ID
     * @param dataScope 数据权限范围
     * @return DTO对象
     */
    public static RolePermissionUpdateDTO createChangeDataScope(Long id, Long updateBy, DataScope dataScope) {
        RolePermissionUpdateDTO dto = new RolePermissionUpdateDTO();
        dto.setId(id);
        dto.setUpdateBy(updateBy);
        dto.setQuickChangeDataScope(dataScope);
        return dto;
    }

    /**
     * 创建修改授权类型DTO
     * @param id 关联ID
     * @param updateBy 更新人ID
     * @param grantType 授权类型
     * @return DTO对象
     */
    public static RolePermissionUpdateDTO createChangeGrantType(Long id, Long updateBy, GrantType grantType) {
        RolePermissionUpdateDTO dto = new RolePermissionUpdateDTO();
        dto.setId(id);
        dto.setUpdateBy(updateBy);
        dto.setQuickChangeGrantType(grantType);
        return dto;
    }
}